package com.yuchen.lucene;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.*;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;


/**
 *
 */
public class SearchHelper {

    private final static Logger LOG = Logger.getLogger(SearchHelper.class);

    private final static int MAX_COUNT = 5000;

    private final static BooleanQuery nullQuery = new BooleanQuery();

    /**
     *
     * @param fieldName lucene field 名称
     * @param q 查询的值
     * @param boost 权重
     * @return
     */
    public static Query makeQuery(String fieldName,String q ,float boost){
        if(StringUtils.isBlank(fieldName) || StringUtils.isBlank(q))
            return nullQuery;
        QueryParser queryParser = new QueryParser(fieldName,LuceneConstant.analyzer);
        queryParser.setDefaultOperator(QueryParser.AND_OPERATOR);
        try {
            Query query = queryParser.parse(q);
            query.setBoost(boost);
            return query;
        } catch (ParseException e) {
            TermQuery termQuery = new TermQuery(new Term(fieldName,q));
            termQuery.setBoost(boost);
            return termQuery;
        }
    }

    /**
     * 搜索
     * @param searcher
     * @param query
     * @param filter
     * @param sort
     * @param page
     * @param count
     * @return
     * @throws IOException
     */
    protected static List<Searchable> find(IndexSearcher searcher, Query query, Filter filter, Sort sort, int page, int count) throws IOException {
        TopDocs hits = null;
        if(filter != null && sort != null)
            hits = searcher.search(query, filter, MAX_COUNT, sort);
        else if(filter != null)
            hits = searcher.search(query, filter, MAX_COUNT);
        else if(sort != null)
            hits = searcher.search(query, MAX_COUNT, sort);
        else
            hits = searcher.search(query, MAX_COUNT);
        if(hits==null) return null;
        List<Searchable> results = new ArrayList<Searchable>();
        int nBegin = (page - 1) * count;
        int nEnd = Math.min(nBegin + count, hits.scoreDocs.length);
        for (int i = nBegin; i < nEnd; i++){
            ScoreDoc s_doc = (ScoreDoc)hits.scoreDocs[i];
            Document doc = searcher.doc(s_doc.doc);
            Searchable obj = DocumentHelper.doc2obj(doc);
            if(obj != null && !results.contains(obj)){
                results.add(obj);
            }
        }
        return results;
    }

    /**
     * 根据查询条件统计搜索结果数
     * @param searcher
     * @param query
     * @param filter
     * @return
     * @throws IOException
     */
    protected static int count(IndexSearcher searcher, Query query, Filter filter) throws IOException {
        try{
            TotalHitCountCollector thcc = new TotalHitCountCollector();
            if(filter != null)
                searcher.search(query,filter,thcc);
            else
                searcher.search(query,thcc);
            return Math.min(MAX_COUNT, thcc.getTotalHits());
        }catch(IOException e){
            LOG.error("Unabled to find via query: " + query, e);
            return -1;
        }
    }
}
